package cn.gjxblog.nio.network.noblocking;

import org.junit.Test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.time.LocalDateTime;
import java.util.Iterator;

/**
 * @author gjx
 * @version v1.0
 * @Description
 * @date 2019/7/24 13:46
 */
public class TestNoBlocking {

    // 客户端
    @Test
    public void client() throws IOException {
        //1 获取通道
        SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));

        //2 切换非阻塞模式
        sChannel.configureBlocking(false);

        //3 分配指定大小的缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        //4 发送数据给服务端
        buffer.put(LocalDateTime.now().toString().getBytes());
        buffer.flip();
        sChannel.write(buffer);
        buffer.clear();

        //5 关闭通道
        sChannel.close();
    }

    @Test
    public  void server() throws IOException {
        //1 获取通道
        ServerSocketChannel ssChannel = ServerSocketChannel.open();

        //2 切换非阻塞模式
        ssChannel.configureBlocking(false);

        //3 绑定连接
        ssChannel.bind(new InetSocketAddress(9898));

        //4 获取选择器
        Selector selector = Selector.open();

        //5 将通道注册到选择器,并且指定监听事件
        ssChannel.register(selector,SelectionKey.OP_ACCEPT);

        //6 轮询式的获取选择器上已经准备就绪的事件
        while(selector.select()>0){
            //7 获取当前选择器中所有注册的选择键（已就绪的监听事件）
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

            //8 获取准备就绪的事件
            while(iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();
                //9 判断具体是什么事件准备就绪
                if(selectionKey.isAcceptable()){
                    //10 若"接收就绪"，获取客户端连接
                    SocketChannel sChannel = ssChannel.accept();

                    //11 切换非阻塞模式
                    sChannel.configureBlocking(false);

                    //12 将通道注册到选择器上
                    sChannel.register(selector,SelectionKey.OP_READ);
                }else if(selectionKey.isReadable()){
                    //13 获取当前 选择器上 "读就绪" 状态的通道
                    SocketChannel channel = (SocketChannel) selectionKey.channel();

                    //14 读取数据
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int len = 0;
                    while((len = channel.read(buffer) )!= -1){
                        buffer.flip();
                        System.out.println(new String(buffer.array(),0,len));
                        buffer.clear();
                    }
                }
                iterator.remove();
            }

        }

    }
}
